package com.hgc.ch04.condition;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Created by 01367627 on 2019/6/27.
 */
public class ProducerAndConsumer {

    private static Lock lock = new ReentrantLock();
    private static Condition condition = lock.newCondition();

    static class Container {
        int index = 0;
        Object[] container;

        Container(int size) {
            if (size <= 0) {
                throw new IllegalArgumentException("容器容量不得小于0！");
            }
            container = new Object[size];
        }

        void produce(Object o, int i) throws InterruptedException {
            lock.lock();
            try {
                while (index == container.length - 1) {
                    condition.await();
                }
                container[index] = o;
                System.out.println(Thread.currentThread().getName() + "生产了第" + (i + 1) + "个,index=" + index);
                index++;
                condition.signalAll();
            } finally {
                lock.unlock();
            }
        }

        Object consume(int i) throws InterruptedException {
            lock.lock();
            Object o = null;
            try {
                while (index == 0) {
                    condition.await();
                }
                o = container[index];
                System.out.println(Thread.currentThread().getName() + "消费了第" + (i + 1) + "个,index=" + index);
                index--;
                condition.signalAll();
                return o;
            } finally {
                lock.unlock();
            }
        }
    }

    static class Producer extends Thread {
        private String name;
        private Container container;

        Producer(String name, Container container) {
            setName(name);
            this.container = container;
        }

        @Override
        public void run() {
            try {
                for (int i = 0; i < 100; i++) {
                    container.produce(new Object(), i);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    static class Consumer extends Thread {
        private String name;
        private Container container;

        Consumer(String name, Container container) {
            setName(name);
            this.container = container;
        }

        @Override
        public void run() {
            try {
                for (int i = 0; i < 10; i++) {
                    container.consume(i);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Container container = new Container(20);
        for (int i = 0; i < 2; i++) {
            Producer p = new Producer("P" + i, container);
            p.start();
        }
        for (int i = 0; i < 20; i++) {
            Consumer c = new Consumer("C" + i, container);
            c.start();
        }
    }


}
